package com.ld.poetry.aop;

import com.ld.poetry.config.PoetryResult;
import com.ld.poetry.constants.CommonConst;
import com.ld.poetry.entity.User;
import com.ld.poetry.enums.CodeMsg;
import com.ld.poetry.enums.PoetryEnum;
import com.ld.poetry.handle.PoetryLoginException;
import com.ld.poetry.handle.PoetryRuntimeException;
import com.ld.poetry.utils.*;
import com.ld.poetry.utils.cache.PoetryCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * 登录检查切面
 * 
 * 该切面用于处理需要登录验证的接口请求，主要功能包括：
 * 1. 验证用户是否已登录
 * 2. 检查用户权限级别
 * 3. 管理 token 过期时间
 * 
 * 使用说明：
 * 1. 在需要登录验证的方法上添加 @LoginCheck 注解
 * 2. 通过 value 参数指定需要的权限级别
 *    - 0: 管理员权限
 *    - 1: 开发者权限
 *    - 2: 普通用户权限
 * 
 * @author sara
 * @since 2021-08-12
 */
@Aspect         // 声明这是一个切面类
@Component      // 将切面注册为 Spring 组件
@Order(0)       // 定义切面的优先级，数字越小优先级越高
@Slf4j          // 使用 Lombok 的日志注解
public class LoginCheckAspect {

    /**
     * 环绕通知，用于处理登录检查
     * 
     * 该方法会在目标方法执行前后进行拦截，主要功能：
     * 1. 检查请求中是否包含有效的 token
     * 2. 验证用户身份和权限
     * 3. 管理 token 的过期时间
     * 
     * @param joinPoint 连接点，包含目标方法的信息
     * @param loginCheck 登录检查注解，包含权限级别信息
     * @return 目标方法的执行结果
     * @throws Throwable 如果权限检查失败或目标方法执行出错
     */
    @Around("@annotation(loginCheck)")
    public Object around(ProceedingJoinPoint joinPoint, LoginCheck loginCheck) throws Throwable {
        // 获取请求中的 token
        String token = PoetryUtil.getToken();
        // 检查 token 是否存在
        if (!StringUtils.hasText(token)) {
            throw new PoetryLoginException(CodeMsg.NOT_LOGIN.getMsg());
        }

        // 从缓存中获取用户信息
        User user = (User) PoetryCache.get(token);

        // 检查用户是否存在
        if (user == null) {
            throw new PoetryLoginException(CodeMsg.LOGIN_EXPIRED.getMsg());
        }

        // 权限检查逻辑
        if (token.contains(CommonConst.USER_ACCESS_TOKEN)) {
            // 普通用户 token 不能访问管理员接口
            if (loginCheck.value() == PoetryEnum.USER_TYPE_ADMIN.getCode() || 
                loginCheck.value() == PoetryEnum.USER_TYPE_DEV.getCode()) {
                return PoetryResult.fail("请输入管理员账号！");
            }
        } else if (token.contains(CommonConst.ADMIN_ACCESS_TOKEN)) {
            // 检查管理员权限
            if (loginCheck.value() == PoetryEnum.USER_TYPE_ADMIN.getCode() && 
                user.getUserType() != PoetryEnum.USER_TYPE_ADMIN.getCode() && 
                user.getUserType() != PoetryEnum.USER_TYPE_DEV.getCode()) {
                return PoetryResult.fail("请输入管理员账号！");
            }
        } else {
            // 无效的 token 类型
            throw new PoetryLoginException(CodeMsg.NOT_LOGIN.getMsg());
        }

        // 检查用户权限级别
        if (loginCheck.value() < user.getUserType()) {
            throw new PoetryRuntimeException("权限不足！");
        }

        // 重置 token 过期时间
        String userId = user.getId().toString();
        boolean flag1 = false;
        if (token.contains(CommonConst.USER_ACCESS_TOKEN)) {
            flag1 = PoetryCache.get(CommonConst.USER_TOKEN_INTERVAL + userId) == null;
        } else if (token.contains(CommonConst.ADMIN_ACCESS_TOKEN)) {
            flag1 = PoetryCache.get(CommonConst.ADMIN_TOKEN_INTERVAL + userId) == null;
        }

        // 更新 token 过期时间
        if (flag1) {
            synchronized (userId.intern()) {
                boolean flag2 = false;
                if (token.contains(CommonConst.USER_ACCESS_TOKEN)) {
                    flag2 = PoetryCache.get(CommonConst.USER_TOKEN_INTERVAL + userId) == null;
                } else if (token.contains(CommonConst.ADMIN_ACCESS_TOKEN)) {
                    flag2 = PoetryCache.get(CommonConst.ADMIN_TOKEN_INTERVAL + userId) == null;
                }

                if (flag2) {
                    // 更新 token 缓存
                    PoetryCache.put(token, user, CommonConst.TOKEN_EXPIRE);
                    if (token.contains(CommonConst.USER_ACCESS_TOKEN)) {
                        PoetryCache.put(CommonConst.USER_TOKEN + userId, token, CommonConst.TOKEN_EXPIRE);
                        PoetryCache.put(CommonConst.USER_TOKEN_INTERVAL + userId, token, CommonConst.TOKEN_INTERVAL);
                    } else if (token.contains(CommonConst.ADMIN_ACCESS_TOKEN)) {
                        PoetryCache.put(CommonConst.ADMIN_TOKEN + userId, token, CommonConst.TOKEN_EXPIRE);
                        PoetryCache.put(CommonConst.ADMIN_TOKEN_INTERVAL + userId, token, CommonConst.TOKEN_INTERVAL);
                    }
                }
            }
        }

        // 执行目标方法
        return joinPoint.proceed();
    }
}
